package cn.com.vs.api;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;

import cn.com.vs.model.FileInfo;
import cn.com.vs.model.Status;
import cn.com.vs.service.StoreService;

import com.alibaba.fastjson.JSONObject;

@Path("/api/file") 
public class FileApi {

	@POST  
	@Path("/{account}/upload")
	@Produces(MediaType.APPLICATION_JSON)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Status upload(@PathParam("account") String account, 
			@FormParam("data") String data,
			@FormParam("filename") String name,
			@FormParam("catalog") String catalog )
	{
		Status status = new Status();
		if( StringUtils.isBlank(name) ){
			status.setOk(false);
			status.setMessage("文件名不允许为空");
		}else{
			String resourceToken = StoreService.getInstance().storeData(account, data, StringUtils.isBlank(catalog)?"data":catalog,name);
			if( resourceToken != null ){
				status.setOk(true);
				status.setMessage( resourceToken );
			}else{
				status.setOk(false);
				status.setMessage("存储数据异常,请检查数据格式是否为base64编码");
			}
		}
		return status;
	}

	@GET
	@Path("/{account}/res/{token}")
	@Produces(MediaType.APPLICATION_JSON)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public FileInfo fetch(@PathParam("account") String account, 
			@PathParam("token") String token )
	{
		FileInfo status = new FileInfo();
		JSONObject resourceData = StoreService.getInstance().getData(account,token);
		if( resourceData != null ){
			status.setOk(true);
			status.setData( resourceData.getString("data") );
			status.setExtType( resourceData.getString("extType") );
			status.setSize( resourceData.getLong("size") );
			status.setFileName( resourceData.getString("fileName") );
		}else{
			status.setOk(false);
			status.setMessage("获取数据异常");
		}
		return status;
	}

	@GET
	@Path("/{account}/list")
	@Produces(MediaType.APPLICATION_JSON)
	public String listResource(@PathParam("account") String account, 
			@DefaultValue("") @QueryParam("token") String id )
	{
		Status status = new Status();
		JSONObject result = StoreService.getInstance().getList(account,id);
		if( result != null ){
			return result.toJSONString();
		}else{
			status.setOk(false);
			status.setMessage("获取列表失败,token无效或指定token资源已经删除");
		}
		return JSONObject.toJSONString(status);
	}
	
	@PUT
	@Path("/{server}/reinit")
	@Produces(MediaType.APPLICATION_JSON)
	public String reinitFileServer(@PathParam("server") String server )
	{
		JSONObject result = null;
		try {
			result = StoreService.getInstance().reinitServer(URLDecoder.decode(server,"UTF-8"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			Status status = new Status();
			status.setOk(false);
			status.setMessage("decode url 异常:"+e.getMessage());
			return JSONObject.toJSONString(status);
		}
		if( result != null ){
			return result.toJSONString();
		}else{
			Status status = new Status();
			status.setOk(false);
			status.setMessage("重新初始化文件服务失败");
			return JSONObject.toJSONString(status);
		}
	}

	@DELETE
	@Path("/{account}/res/{token}")
	@Produces(MediaType.APPLICATION_JSON)
	public Status del(@PathParam("account") String account, 
			@PathParam("token") String token )
	{
		Status status = new Status();
		boolean ret = StoreService.getInstance().delData(account,token);
		if( ret ){
			status.setOk(true);
			status.setMessage( "资源成功删除" );
		}else{
			status.setOk(false);
			status.setMessage("资源删除失败");
		}
		return status;
	}
	
	@POST  
	@Path("/multipartUpload")
	@Produces(MediaType.APPLICATION_JSON)
	@Consumes(MediaType.MULTIPART_FORM_DATA)
	public String multipartUpload(@Context HttpServletRequest request)
	{
		Status status = new Status();
		try {
			if (ServletFileUpload.isMultipartContent(request)) {
				String account = request.getParameter("account");
				String type = request.getParameter("catalog");
				FileItemFactory factory = new DiskFileItemFactory();
				ServletFileUpload upload = new ServletFileUpload(factory);
				List<FileItem> items = null;
				try {
					items = upload.parseRequest(request);
				} catch (FileUploadException e) {
					e.printStackTrace();
					status.setOk(false);
					status.setMessage("parse request exception:"+e.getMessage());
					return JSONObject.toJSONString(status);
				}
				if (items != null) {
					Iterator<FileItem> iter = items.iterator();
					JSONObject result = new JSONObject();
					int uploadCount = 0;
					while (iter.hasNext()) {
						FileItem item = iter.next();
						if (!item.isFormField() && item.getSize() > 0) {
							String fileName = processFileName(item.getName());
							try {
								InputStream is = item.getInputStream();
								ByteArrayOutputStream out = new ByteArrayOutputStream();
								byte[] temp = new byte[1024];
								StringBuilder sb = new StringBuilder();
								for(int len = is.read(temp); len != -1;len = is.read(temp)){
									out.write(temp, 0, len);
									sb.append(Base64.encodeBase64URLSafeString(temp));
									out.reset();
								}
								String resourceToken = StoreService.getInstance().storeData(account, sb.toString(), 
										StringUtils.isBlank(type)?"data":type,fileName);
								if( resourceToken != null ){
									result.put(fileName, resourceToken);
									uploadCount++;
								}else{
									result.put(fileName, "");
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
					result.put("ok", true);
					result.put("msg", String.valueOf(uploadCount) );
					return result.toJSONString();
				}else{
					status.setOk(false);
					status.setMessage("no data to store");
				}
			}else{
				status.setOk(false);
				status.setMessage("not multi-part upload request");
			}
		} catch (Exception e) {
			status.setOk(false);
			status.setMessage("multi-part upload exception:"+e.getMessage());
		}
		return JSONObject.toJSONString(status);
	}

	private String processFileName(String fileNameInput) {
		String fileNameOutput = null;
		fileNameOutput = fileNameInput.substring(
				fileNameInput.lastIndexOf("\\") + 1, fileNameInput.length());
		return fileNameOutput;
	}
}